package com.haiqiu.file.oss.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.haiqiu.file.constant.Constants;
import com.haiqiu.file.oss.config.OssConfig;
import com.haiqiu.tools.common.utils.FileToolsUtils;
import com.haiqiu.tools.common.utils.HttpServletUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;

/**
 * @author HaiQiu
 * @since 2023/3/3
 */
public class OssUtils {

    private static final Logger log = LoggerFactory.getLogger(OssUtils.class);

    /**
     * endpoint是访问OSS的域名。如果您已经在OSS的控制台上 创建了Bucket，请在控制台上查看域名。
     */
    public static String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";

    /**
     * accessKeyId和accessKeySecret是OSS的访问密钥，您可以在控制台上创建和查看，
     */
    public static String accessKeyId = "<yourAccessKeyId>";
    /**
     * accessKeyId和accessKeySecret是OSS的访问密钥，您可以在控制台上创建和查看，
     */
    public static String accessKeySecret = "<yourAccessKeySecret>";

    /**
     * Bucket用来管理所存储Object的存储空间，详细描述请参看“开发人员指南 > 基本概念 > OSS基本概念介绍”。
     */
    public static String bucketName = "<yourBucketName>";

    /**
     * 访问域名配置
     */
    private static String host = "https://haiqiu123.oss-cn-chengdu.aliyuncs.com";


    public static void init(OssConfig ossConfig) {
        accessKeyId = ossConfig.getAccessKeyId();
        accessKeySecret = ossConfig.getAccessKeySecret();
        endpoint = ossConfig.getEndpoint();
        bucketName = ossConfig.getBucketName();
        host = ossConfig.getHost();
    }


    public static String uploadFile(String remotePath, MultipartFile multipartFile) {
        String fileName = FileToolsUtils.createOssFileName(remotePath, multipartFile);
        boolean b = false;
        try {
            b = upload(fileName, multipartFile.getInputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        if (b) {
            if (!host.endsWith(Constants.CARVE)) {
                host = host + Constants.CARVE;
            }
            return host + fileName;
        }
        return null;
    }


    public static boolean upload(String keyName, InputStream input) {
        //获取客户端
        OSS ossClient = getClient();
        // 查看Bucket信息。详细请参看“SDK手册 > Java-SDK > 管理Bucket”。
        // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_bucket.html?spm=5176.docoss/sdk/java-sdk/init
        BucketInfo info = ossClient.getBucketInfo(bucketName);
        log.info("Bucket " + bucketName + "的信息如下：");
        log.info("\t数据中心：" + info.getBucket().getLocation());
        log.info("\t创建时间：\" + info.getBucket().getCreationDate()");
        log.info("\t用户标志：\" + info.getBucket().getOwner()");

        // 把字符串存入OSS，Object的名称为firstKey。详细请参看“SDK手册 > Java-SDK > 上传文件”。
        // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/upload_object.html?spm=5176.docoss/user_guide/upload_object
        //InputStream is = new ByteArrayInputStream("Hello OSS".getBytes());
        //设置文件类型
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(getContentType(keyName.substring(keyName.lastIndexOf("."))));

        ossClient.putObject(bucketName, keyName, input, objectMetadata);
        log.info("Object：" + keyName + "存入OSS成功。");
        return true;
    }


    /**
     * 查看oss集合列表
     *
     * @param prefix 路径前缀
     * @return 集合信息
     */
    public static List<OSSObjectSummary> list(String prefix) {
        //获取客户端
        OSS ossClient = getClient();
        // 查看Bucket中的Object。详细请参看“SDK手册 > Java-SDK > 管理文件”。
        // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_object.html?spm=5176.docoss/sdk/java-sdk/manage_bucket
        ObjectListing objectListing = null;
        if (prefix == null) {
            objectListing = ossClient.listObjects(bucketName);
        } else {
            objectListing = ossClient.listObjects(bucketName, checkOssFileName(prefix));
        }
        List<OSSObjectSummary> objectSummary = objectListing.getObjectSummaries();
        log.info("您有以下Object：");
        for (OSSObjectSummary object : objectSummary) {
            log.info("\t" + object.getKey());
        }
        return objectSummary;
    }

    /**
     * 删除oss文件
     *
     * @param remotePath 文件地址
     * @return 是否成功
     */
    public static boolean deleteFile(String remotePath) {
        //获取客户端
        OSS ossClient = getClient();
        //获取文件地址
        remotePath = getRemotePath(remotePath);
        // 删除Object。详细请参看“SDK手册 > Java-SDK > 管理文件”。
        // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_object.html?spm=5176.docoss/sdk/java-sdk/manage_bucket
        ossClient.deleteObject(bucketName, remotePath);
        log.info("删除Object " + remotePath + " 成功。");
        return true;
    }

    /**
     * 创建oss文件上传随机文件名
     *
     * @param destPath 目标目录
     * @return 正确的oss地址名称
     */
    public static String checkOssFileName(String destPath) {
        if (destPath.startsWith(Constants.CARVE)) {
            destPath = destPath.substring(1);
        }
        if (!destPath.endsWith(Constants.CARVE)) {
            destPath = destPath + Constants.CARVE;
        }
        return destPath;
    }

    /**
     * 创建oss连接客户端
     *
     * @return OSS
     */
    private static OSS getClient() {
        // 生成OSSClient，您可以指定一些参数，详见“SDK手册 > Java-SDK > 初始化”，
        // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/init.html?spm=5176.docoss/sdk/java-sdk/get-start
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 判断Bucket是否存在。详细请参看“SDK手册 > Java-SDK > 管理Bucket”。
        // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_bucket.html?spm=5176.docoss/sdk/java-sdk/init
        if (ossClient.doesBucketExist(bucketName)) {
            log.info("您已经创建Bucket：" + bucketName + "。");
        } else {
            log.info("您的Bucket不存在，创建Bucket：" + bucketName + "。");
            // 创建Bucket。详细请参看“SDK手册 > Java-SDK > 管理Bucket”。
            // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/manage_bucket.html?spm=5176.docoss/sdk/java-sdk/init
            ossClient.createBucket(bucketName);
        }
        return ossClient;
    }

    public static String getContentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        if (FilenameExtension.equalsIgnoreCase(".json")) {
            return "application/json";
        }
        if (FilenameExtension.equalsIgnoreCase(".webp")) {
            return "image/jpg";
        }
        return "application/octet-stream";
    }


    public static byte[] download(String remotePath) {
        remotePath = getRemotePath(remotePath);
        // 生成OSSClient，您可以指定一些参数，详见“SDK手册 > Java-SDK > 初始化”，
        // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/init.html?spm=5176.docoss/sdk/java-sdk/get-start
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 下载文件。详细请参看“SDK手册 > Java-SDK > 下载文件”。
        // 链接地址是：https://help.aliyun.com/document_detail/oss/sdk/java-sdk/download_object.html?spm=5176.docoss/sdk/java-sdk/manage_object
        OSSObject ossObject = ossClient.getObject(bucketName, remotePath);
        InputStream inputStream = ossObject.getObjectContent();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        if (inputStream == null) {
            throw new RuntimeException("文件不存在");
        }
        int size;
        byte[] buff = new byte[10240];
        try {
            while ((size = inputStream.read(buff)) > 0) {
                out.write(buff, 0, size);
                out.flush();
            }
            byte[] bytes = out.toByteArray();
            out.close();
            inputStream.close();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
        return null;
    }


    /**
     * 获取remotePath地址
     *
     * @param remotePath 文件远程地址
     * @return 文件远程地址
     */
    private static String getRemotePath(String remotePath) {
        if (!StringUtils.hasText(remotePath)) {
            throw new RuntimeException("文件地址为空");
        }
        if (remotePath.toLowerCase().startsWith(Constants.HTTP)) {
            remotePath = remotePath.replaceAll(host, "");
        }
        if (remotePath.startsWith(Constants.CARVE)) {
            remotePath = remotePath.substring(1);
        }
        return remotePath;
    }

    /**
     * 下载文件为字节
     *
     * @param remoteFilePath 文件地址
     * @return 字节
     */

    public static void downloadFile(String remoteFilePath) {
        byte[] bytes = download(remoteFilePath);
        String fileName = remoteFilePath.substring(remoteFilePath.lastIndexOf(Constants.CARVE) + 1);
        export(fileName, bytes, HttpServletUtils.getServletResponse());
    }

    /**
     * 导出文件流
     *
     * @param fileName 文件名
     * @param bytes    文件铺
     * @param response 输出流
     */
    private static void export(String fileName, byte[] bytes, HttpServletResponse response) {
        try (OutputStream ouputStream = response.getOutputStream()) {
            // 设置输出的格式
            String name = URLEncoder.encode(fileName, "UTF-8");
            //自定义的header
            response.setHeader("requestType", "file");
            // 自定义的header
            response.setHeader("requestFileName", name);
            //设置这个header 可见
            response.setHeader("Access-Control-Expose-Headers", "requestType,requestFileName");

            //设置响应类型为html，编码为utf-8，处理相应页面文本显示的乱码
            response.setContentType("application/octet-stream;charset=UTF-8");
            //设置文件头：最后一个参数是设置下载文件名
            response.setHeader("Content-disposition", "attachment;fileName=" + name);
            ouputStream.write(bytes);
            ouputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
